﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Linq;
using System.ComponentModel;
using System.Windows.Controls.DataVisualization.Charting;
using System8ToyMC.Plots;

namespace System8ToyMC
{
	public partial class Histogram : UserControl
	{
		public Histogram()
		{
            //
			// Required to initialize variables
            //

            InitializeComponent();
            LayoutRoot.DataContext = this;
		}

        /// <summary>
        /// Name of the x-axis (becomes plot title)
        /// </summary>
        public string XAxisName
        {
            get { return (string)GetValue(XAxisNameProperty); }
            set { SetValue(XAxisNameProperty, value); }
        }

        // Using a DependencyProperty as the backing store for XAxisName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty XAxisNameProperty =
            DependencyProperty.Register("XAxisName", typeof(string), typeof(Histogram), new PropertyMetadata(""));


        /// <summary>
        /// Gets the interval used to display the histogram. It is automatically set
        /// each time the histogram data is calculated... changing it can help, but it
        /// won't last through the next update. :(
        /// </summary>
        public double AxisLabelInterval
        {
            get { return (double)GetValue(AxisLabelIntervalProperty); }
            set { SetValue(AxisLabelIntervalProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AxisLabelInterval.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AxisLabelIntervalProperty =
            DependencyProperty.Register("AxisLabelInterval", typeof(double), typeof(Histogram), new PropertyMetadata(0.0));


        /// <summary>
        /// Get/Set the histogram values. Must be totally replaced for
        /// an update to occur!
        /// </summary>
        public double[] HistogramValues
        {
            set { System.Threading.ThreadPool.QueueUserWorkItem(o => UpdateHistogramValuesOnBackgroundThread(value)); }
        }

        /// <summary>
        /// Tmep class to hold the bin-data for the histogram.
        /// </summary>
        public class BinData
        {
            public double BinValue { get; set; }
            public double Content { get; set; }
        }

        /// <summary>
        /// Get the internal set of values that will be shown on the plot itself.
        /// </summary>
        public BinData[] Values
        {
            get { return (BinData[])GetValue(ValuesProperty); }
            private set { SetValue(ValuesProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Values.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValuesProperty =
            DependencyProperty.Register("Values", typeof(BinData[]), typeof(Histogram), new PropertyMetadata(null));

        /// <summary>
        /// Bin the histogram, and then cache it!
        /// </summary>
        private void UpdateHistogramValuesOnBackgroundThread(double[] vals)
        {
            ///
            /// Create the histogram using a histogram class
            /// 

            var hmgr = new HistogramData(50);
            foreach (var theVal in vals)
            {
                hmgr.Accumulate(theVal);
            }

            int ibins = (int) hmgr.Dimension;
            BinData[] bins = new BinData[ibins];
            for (int i = 0; i < ibins; i++)
            {
                bins[i] = new BinData() { Content = hmgr.YValueAt(i), BinValue = hmgr.XValueAt(i) };
            }

            ///
            /// Get the interval set that we are going to be using to
            /// get the # of "tick counts" right with
            /// 

            double interval = (hmgr.Maximum - hmgr.Minimum) / 10.0;

            ///
            /// Update teh display
            /// 

            Dispatcher.BeginInvoke(() =>
                {
                    Values = bins;
                    AxisLabelInterval = interval;
                });
        }

        /// <summary>
        /// Clone ourselves!
        /// </summary>
        /// <returns></returns>
        public Histogram CloneHistogram()
        {
            Histogram r = new Histogram();

            Dispatcher.BeginInvoke(() =>
                {
                    r.XAxisName = XAxisName;
                    r.Values = Values;
                    r.AxisLabelInterval = AxisLabelInterval;
                });

            return r;
        }
    }

}